Skip to content

feat: support full user targeting on workflow USER TASK#171

Open
engalar wants to merge 3 commits intomendixlabs:mainfrom
engalar:fix/issue-169-workflow-target-users
Open

feat: support full user targeting on workflow USER TASK#171
engalar wants to merge 3 commits intomendixlabs:mainfrom
engalar:fix/issue-169-workflow-target-users

Conversation

@engalar
Copy link
Copy Markdown
Contributor

@engalar engalar commented Apr 10, 2026

Fixes #169

Summary

  • Parser now reads both legacy UserSource and current UserTargeting BSON fields, recognizing all five $Type variants (MicroflowUserTargeting, XPathUserTargeting, MicroflowGroupTargeting, XPathGroupTargeting, NoUserTargeting)
  • Added MicroflowGroupSource and XPathGroupSource SDK types with full BSON serialization/deserialization
  • MDL grammar extended with optional USERS/GROUPS modifier: TARGETING [USERS|GROUPS] MICROFLOW/XPATH
  • DESCRIBE output now correctly displays all targeting types including group targeting

Syntax

-- User targeting (existing, backward compatible)
TARGETING MICROFLOW Module.GetUsers
TARGETING XPATH '[System.UserRoles = ''[%UserRole_Manager%]'']'

-- Explicit user targeting (new)
TARGETING USERS MICROFLOW Module.GetUsers
TARGETING USERS XPATH '[...]'

-- Group targeting (new)
TARGETING GROUPS MICROFLOW Module.GetGroups
TARGETING GROUPS XPATH '[GroupType = ''Reviewers'']'

Test plan

  • 6 new parser tests covering all targeting types (user microflow/xpath, group microflow/xpath, no targeting, legacy UserSource)
  • mxcli check validates all syntax variants
  • Full test suite passes
  • Build succeeds

This was referenced Apr 10, 2026
Copy link
Copy Markdown
Collaborator

@ako ako left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix with thoughtful backward compatibility.

What's good

Backward compatibility done right. Parser reads both legacy UserSource and current UserTargeting fields, mapping old and new $Type variants to the same SDK types — projects from any Mendix version round-trip.

Grammar extension is non-breaking. TARGETING (USERS | GROUPS)? keeps existing scripts working.

Full pipeline coverage across all 7 layers (SDK, parser, writer, grammar, AST, visitor, executor, formatter).

Good test coverage — 6 parser tests covering all targeting variants including the legacy field.

Concerns

XPathConstraint fallback may be reversed. Parser checks XPath first, then falls back to XPathConstraint, but the writer always emits XPathConstraint. If real Mendix BSON uses XPathConstraint, the XPath check is dead code; if both exist in different versions, the priority should match what's actually used.

Group source types may be missing fields. MicroflowGroupSource only stores Microflow. If group targeting has additional fields (e.g., context variable like user targeting may have), they'd be silently lost. Worth verifying against a real Studio Pro export.

MULTI USER TASK grammar duplication. Identical targeting blocks in both USER TASK and MULTI USER TASK rules — could be factored into a userTargetingClause rule. Not blocking.

Visitor's group detection is coarse. len(utCtx.AllGROUPS()) > 0 flags both microflow and xpath as group if either uses GROUPS. Probably impossible in practice (only one targeting clause allowed) but worth a guard.

No DESCRIBE roundtrip test. Tests cover parsing only. A test that creates → describes → re-parses would catch formatter mismatches.

LGTM — fix is correct, concerns are minor improvements.

@engalar engalar force-pushed the fix/issue-169-workflow-target-users branch from b25df6d to e4ca07b Compare April 13, 2026 05:10
@github-actions
Copy link
Copy Markdown

AI Code Review

What Looks Good

  • The implementation correctly extends existing MDL syntax rather than creating new statements, maintaining consistency with current patterns
  • Reuses existing AST structure efficiently (same Microflow/XPath fields for both user and group targeting)
  • Follows the established pattern for optional modifiers in MDL grammar
  • Includes both USERS (explicit) and GROUPS options for clarity and explicit intent
  • Maintains backward compatibility with legacy UserSource targeting
  • Properly updates all layers of the stack: grammar → AST → visitor (implied) → executor → LSP
  • Includes DESCRIBE roundtrip consideration in formatting logic that outputs re-executable MDL
  • Updates LSP completions for proper IDE support in VS Code extension

Recommendation

The PR appears to be well-implemented and follows all the necessary guidelines from CLAUDE.md. It addresses the full stack consistently, maintains backward compatibility, follows MDL design principles, and includes appropriate test coverage as claimed in the PR body.

Approve this pull request.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@engalar engalar force-pushed the fix/issue-169-workflow-target-users branch from e4ca07b to 5386fc4 Compare April 13, 2026 06:14
Copy link
Copy Markdown
Collaborator

@ako ako left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: feat: support full user targeting on workflow USER TASK

Overall: Clean, well-scoped PR that adds group targeting support for workflow user tasks. The implementation follows existing patterns correctly and the test coverage is solid. A few items to address:

Issues

1. DESCRIBE output for existing user targeting types misses USERS modifier

The DESCRIBE formatter (cmd_workflows.go:426-433) outputs TARGETING MICROFLOW and TARGETING XPATH for existing user-targeting types, but the new syntax supports TARGETING USERS MICROFLOW. While backward-compatible (the grammar makes USERS/GROUPS optional), this creates an asymmetry: group targeting always outputs TARGETING GROUPS MICROFLOW but user targeting never outputs TARGETING USERS MICROFLOW. If a user reads DESCRIBE output, they might not realize the USERS modifier exists. Consider whether DESCRIBE should emit the explicit form for clarity once group targeting is in play.

2. Writer serializes UserTargeting but parser reads both UserSource and UserTargeting — field name inconsistency

The writer (writer_workflow.go) serializes into the UserTargeting BSON field (the current name), which is correct. The parser reads both UserSource (legacy) and UserTargeting (current) — also correct. However, there's no comment or constant explaining which Mendix versions use which field name. The PR description mentions "Mendix 10.12+" for UserTargeting — a brief comment in parser_workflow.go at the fallback would help future maintainers.

3. NoUserTargeting not explicitly handled in parseUserSource

The default case in parseUserSource (parser_workflow.go:598) returns &workflows.NoUserSource{} which implicitly handles Workflows$NoUserTargeting. This works, but adding it as an explicit case alongside NoUserSource would make the code self-documenting and prevent accidental regression if someone later adds logging for the default case.

4. Grammar allows both TARGETING USERS MICROFLOW and TARGETING USERS XPATH on the same task

The grammar rule has two separate optional clauses:

(TARGETING (USERS | GROUPS)? MICROFLOW qualifiedName)?
(TARGETING (USERS | GROUPS)? XPATH STRING_LITERAL)?

This means a user could write both on the same task. The visitor code would set Kind twice (once to microflow, then overwritten by xpath). This is pre-existing behavior, not introduced by this PR, but worth noting.

5. Missing BSON fields for group sources

MicroflowGroupTargeting and XPathGroupTargeting — the parser doesn't read XPath as a fallback field for MicroflowGroupTargeting (unlike the existing MicroflowBasedUserSource which reads MicroflowExpression as fallback). Are there any additional BSON fields on these types? If you've verified against real Studio Pro output, this is fine — but worth confirming.

Positives

  • Backward compatibility: Legacy UserSource field is still read, with UserTargeting as fallback — existing MPR files continue to work.
  • Test coverage: 6 well-structured tests covering all targeting types including legacy.
  • Full-stack wiring: Grammar, visitor, AST, executor (read + write), parser, writer, SDK types, and LSP completions all updated consistently.
  • Clean scope: Single feature, single commit — follows the PR checklist.

Checklist items to verify

  • make grammar was run (generated files are included, looks correct)
  • No mdl-examples/doctype-tests/ test files for the new syntax variants — the PR checklist says MDL syntax changes should include working examples
  • No version-gating for group targeting — if this requires Mendix 10.12+, should checkFeature() be called?
  • Quick reference (docs/01-project/MDL_QUICK_REFERENCE.md) not updated with the new GROUPS modifier

@engalar engalar requested a review from ako April 13, 2026 07:35
@ako
Copy link
Copy Markdown
Collaborator

ako commented Apr 13, 2026

Follow-up review after ef0f3e5

The new commit adds GROUPS to the keyword rule in MDLParser.g4 — correct fix for TestKeywordRuleCoverage. No issues with this change.

The substantive items from my previous review still apply:

  1. DESCRIBE asymmetry — user targeting outputs TARGETING MICROFLOW while group targeting outputs TARGETING GROUPS MICROFLOW. Consider emitting TARGETING USERS MICROFLOW for symmetry.
  2. Version comment — the UserSourceUserTargeting field name transition (Mendix 10.12+) deserves a comment in parser_workflow.go. (Partially addressed — the comments are there now but a version note would help.)
  3. Explicit NoUserTargeting case — still handled implicitly by the default branch in parseUserSource.
  4. Missing mdl-examples/doctype-tests/ — no working MDL examples for the new syntax variants.
  5. No version-gating — if group targeting requires Mendix 10.12+, should checkFeature() guard it?
  6. Quick reference not updateddocs/01-project/MDL_QUICK_REFERENCE.md doesn't mention the GROUPS modifier.

Otherwise LGTM — the core implementation is solid.

This was referenced Apr 13, 2026
engalar and others added 3 commits April 15, 2026 09:34
…labs#169)

Parser now reads both legacy UserSource and current UserTargeting BSON
fields, recognizing all five $Type variants: MicroflowUserTargeting,
XPathUserTargeting, MicroflowGroupTargeting, XPathGroupTargeting, and
NoUserTargeting. MDL syntax extended with optional USERS/GROUPS modifier:
TARGETING [USERS|GROUPS] MICROFLOW/XPATH.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DESCRIBE output now emits explicit TARGETING USERS for user targeting
  types (symmetry with TARGETING GROUPS)
- Add version history comment for UserSource vs UserTargeting field names
- Add explicit NoUserSource/NoUserTargeting case in parseUserSource
- Swap XPathConstraint/XPath priority to match writer output
- Add doctype-test for all targeting variants
- Update quick reference with GROUPS modifier

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@engalar engalar force-pushed the fix/issue-169-workflow-target-users branch from ef0f3e5 to e17e51d Compare April 15, 2026 01:41
@github-actions
Copy link
Copy Markdown

AI Code Review

Let me analyze this PR review request carefully. I need to review the PR titled "feat: support full user targeting on workflow USER TASK" against the provided checklist and project context.

First, let me understand what this PR does based on the description:

  1. It fixes issue Support TARGET USERS clause on workflow USER TASK definitions #169
  2. It adds support for both legacy UserSource and current UserTargeting BSON fields
  3. It recognizes all five $Type variants: MicroflowUserTargeting, XPathUserTargeting, MicroflowGroupTargeting, XPathGroupTargeting, NoUserTargeting
  4. It adds MicroflowGroupSource and XPathGroupSource SDK types with BSON serialization/deserialization
  5. It extends MDL grammar with optional USERS/GROUPS modifier: TARGETING [USERS|GROUPS] MICROFLOW/XPATH
  6. It updates DESCRIBE output to correctly display all targeting types including group targeting

The PR includes changes to:

  • cmd/mxcli/lsp_completions_gen.go - Added "GROUPS" keyword
  • docs/01-project/MDL_QUICK_REFERENCE.md - Updated workflow activity syntax to show [USERS|GROUPS] options
  • mdl-examples/doctype-tests/workflow-user-targeting.mdl - New test file showing all targeting variants
  • mdl/ast/ast_workflow.go - Updated WorkflowTargetingNode to support group targeting kinds
  • mdl/executor/cmd_workflows.go - Updated formatUserTask to handle group targeting in DESCRIBE output
  • mdl/executor/cmd_workflows_write.go - Updated buildUserTask to handle group targeting when building from AST
  • mdl/grammar/MDLLexer.g4 - Added GROUPS token
  • mdl/grammar/MDLParser.g4 - Updated workflowUserTaskStmt to allow optional USERS/GROUPS modifier
  • mdl/grammar/parser/ - Generated parser files (noise, to be skipped per instructions)
  • mdl/grammar/MDLParser.g4 - Added GROUPS to keyword list

Now I'll review this against the checklist:

Overlap & duplication

  • Check proposals list: No proposals directory mentioned, so skip
  • Check for duplicate implementations: This appears to be new functionality for group targeting in workflow user tasks, not duplicating existing code
  • Check doctype test files: The PR adds a new test file workflow-user-targeting.mdl which is appropriate
  • Re-documenting shipped features: This is adding new functionality (group targeting), not re-documenting existing features

MDL syntax design

Let me check if the new/ modified MDL syntax follows the guidelines:

The PR modifies the syntax from:

TARGETING MICROFLOW qualifiedName
TARGETING XPATH STRING_LITERAL

To:

TARGETING (USERS | GROUPS)? MICROFLOW qualifiedName
TARGETING (USERS | GROUPS)? XPATH STRING_LITERAL

Checking against the guidelines:

  • ✅ Follows standard CREATE/ALTER/DROP/SHOW/DESCRIBE pattern - This is modifying TARGETING which is part of USER TASK statement (not a CRUD verb itself, but TARGETING is a modifier)
  • ✅ Uses Module.Element qualified names everywhere - The microflow references still use qualified names
  • ✅ Property lists use ( Key: value, ... ) format - Not applicable here as this is a modifier, not a property list
  • ✅ Colon for property definitions, AS for name-to-name mappings - Not applicable here
  • ❌ Keywords are full English words - "USERS" and "GROUPS" are abbreviations/plurals, but they're standard English words. Let me check if this violates the guideline.
  • ✅ Statement reads as English - "TARGETING USERS MICROFLOW" reads as English
  • ❌ No keyword overloading - Need to check if USERS/GROUPS are overloaded elsewhere
  • ✅ Diff-friendly - Adding one property would be a one-line diff (not directly applicable here)
  • ✅ Consistent with existing MDL patterns - Looking at existing patterns, we have similar modifiers in other places

Let me check the design-mdl-syntax.md skill as instructed in the checklist:

From the checklist: "[ ] Design skill consulted — read .claude/skills/design-mdl-syntax.md before designing syntax"

I should verify if the syntax follows the principles in that skill. Since I don't have the actual content of that file, I'll rely on the checklist description which says:

"New MDL syntax must follow design guidelines: reads as English (target audience is citizen developers), uses standard CRUD verbs (CREATE/ALTER/DROP/SHOW/DESCRIBE), consistent property format (Key: value) for property definitions, AS for name-to-name mappings (old AS new), qualified names (Module.Element), no keyword overloading, no symbolic syntax."

Let me evaluate:

  • Reads as English: "TARGETING USERS MICROFLOW" - Yes, this reads as English
  • Standard CRUD verbs: TARGETING isn't a CRUD verb, but it's a modifier within USER TASK statement which is a CREATE-like statement
  • Property format: Not applicable here as this is a modifier
  • AS for name-to-name mappings: Not applicable here
  • Qualified names: The microflow references still use qualified names like Module.GetUsers
  • No keyword overloading: I need to check if USERS or GROUPS are used elsewhere as keywords with different meanings
  • No symbolic syntax: Uses words, not symbols

Let me check if USERS or GROUPS are overloaded elsewhere in the grammar:

Looking at the diff:

  • In MDLLexer.g4: Added USERS and GROUPS tokens
  • In MDLParser.g4: Added them to the keyword list and used in workflowUserTaskStmt
  • In lsp_completions_gen.go: Added as keywords

I should check if these tokens conflict with existing usage. Since this is a workflow-specific context (inside USER TASK statement), and USERS/GROUPS aren't likely used elsewhere in conflicting ways, this seems acceptable.

The guideline says: "IMPORTANT: colon is for property definitions (Key: value), AS is for name-to-name mappings — do not flag AS in mapping contexts as a syntax violation." This doesn't apply here.

Full-stack consistency for MDL features

Let me check if the feature is wired through the full pipeline:

  • ✅ Grammar: Rule added to MDLParser.g4 (and MDLLexer.g4 for new tokens GROUPS)
  • ✅ Parser regenerated: The diff shows changes to parser/ files, so make grammar was likely run
  • ✅ AST: Node type added in mdl/ast/ - WorkflowTargetingNode updated to support group targeting kinds
  • ✅ Visitor: Not explicitly shown in diff, but the AST changes would require visitor updates. Let me check if visitor files are missing from the diff...
    • Actually, looking at the diff, I don't see explicit changes to mdl/visitor/. But the AST node changed, so the visitor would need to be updated to populate the new fields. This might be a gap.
  • ✅ Executor: Handler in mdl/executor/ - Changes to cmd_workflows.go and cmd_workflows_write.go
  • ⚠️ LSP: Changes to lsp_completions_gen.go for keyword completion, but need to check if other LSP features (formatting, diagnostics, navigation) are needed
  • ✅ DESCRIBE roundtrip: Changes to cmd_workflows.go show that formatUserTask now outputs the USERS/GROUPS prefixes, so DESCRIBE should work
  • ⚠️ VS Code extension: Not explicitly shown in diff, but LSP completion was updated

Let me double-check the visitor part. The AST node WorkflowTargetingNode was updated in mdl/ast/ast_workflow.go to have:

Kind      string        // "microflow", "xpath", "group_microflow", "group_xpath", or ""
Microflow QualifiedName // for microflow targeting (user or group)
XPath     string        // for xpath targeting (user or group)

For the visitor to set these correctly when parsing the new syntax, we would need changes in the visitor code. However, the visitor code isn't shown in the diff. This could be an issue.

Actually, looking more carefully at the PR description: "Generated ANTLR parser files (mdl/grammar/parser/) are noise — note but skip." But the visitor is separate from the parser.

Let me think about how ANTLR works:

  1. Grammar files (.g4) generate parser and lexer
  2. We have a visitor that walks the parse tree to create AST nodes
  3. The AST node definition is in mdl/ast/
  4. The visitor implementation is in mdl/visitor/

If the AST node changed, we likely need to update the visitor to populate the new fields based on the parsed syntax.

Since the visitor files aren't in the diff, this might be a missing piece.

However, looking at the executor changes, particularly in cmd_workflows_write.go:

func buildUserTask(n *ast.WorkflowUserTaskNode) *workflows.UserTask {
    // ...
    switch n.Targeting.Kind {
    case "microflow":
        // ...
    case "xpath":
        // ...
    case "group_microflow":
        task.UserSource = &workflows.MicroflowGroupSource{
            Microflow: n.Targeting.Microflow.Module + "." + n.Targeting.Microflow.Name,
        }
    case "group_xpath":
        task.UserSource = &workflows.XPathGroupSource{
            XPath: n.Targeting.XPath,
        }
    }
    // ...
}

This shows that the executor is expecting the visitor to have set:

  • n.Targeting.Kind to "group_microflow" or "group_xpath" for group targeting
  • n.Targeting.Microflow for microflow targeting (both user and group)
  • n.Targeting.XPath for xpath targeting (both user and group)

So the visitor must have been updated to set these values based on whether USERS or GROUPS was present in the TARGETING clause.

Since the visitor code isn't in the diff, I need to determine if this is an omission or if the visitor changes were made elsewhere.

Actually, looking at the PR diff again, I don't see any changes to mdl/visitor/. This is concerning because if the AST node changed but the visitor wasn't updated, the Kind field wouldn't be set correctly.

Let me check if there's a visitor file that would handle this. Typically, for workflow user tasks, there would be something like mdl/visitor/workflow_visitor.go or similar.

Since it's not in the diff, this might be a missing piece.

Wait, let me look at the AST change again:

// WorkflowTargetingNode represents user targeting strategy.
// Kind: "microflow", "xpath", "group_microflow", "group_xpath", or ""
type WorkflowTargetingNode struct {
	Kind      string        // "microflow", "xpath", "group_microflow", "group_xpath", or ""
	Microflow QualifiedName // for microflow targeting (user or group)
	XPath     string        // for xpath targeting (user or group)
}

And the grammar change:

(TARGETING (USERS | GROUPS)? MICROFLOW qualifiedName)?
(TARGETING (USERS | GROUPS)? XPATH STRING_LITERAL)?

So when parsing:

  • TARGETING MICROFLOW x.y should set Kind="microflow"
  • TARGETING USERS MICROFLOW x.y should set Kind="microflow" (but we need to know it's explicit users)
  • TARGETING GROUPS MICROFLOW x.y should set Kind="group_microflow"
  • Similarly for XPATH

Actually, looking at the Kind values in the comment: "microflow", "xpath", "group_microflow", "group_xpath", or ""

This suggests:

  • "microflow" = legacy/user microflow targeting (TARGETING MICROFLOW or TARGETING USERS MICROFLOW)
  • "xpath" = legacy/user xpath targeting (TARGETING XPATH or TARGETING USERS XPATH)
  • "group_microflow" = TARGETING GROUPS MICROFLOW
  • "group_xpath" = TARGETING GROUPS XPATH

But wait, how does the visitor distinguish between legacy TARGETING MICROFLOW and explicit TARGETING USERS MICROFLOW? Both would set Kind="microflow" according to this.

Looking at the executor formatUserTask function:

switch us := a.UserSource.(type) {
case *workflows.MicroflowBasedUserSource:
    if us.Microflow != "" {
        lines = append(lines, fmt.Sprintf("%s  TARGETING USERS MICROFLOW %s", indent, us.Microflow))
    }
case *workflows.XPathBasedUserSource:
    if us.XPath != "" {
        lines = append(lines, fmt.Sprintf("%s  TARGETING USERS XPATH '%s'", indent, us.XPath))
    }
case *workflows.MicroflowGroupSource:
    if us.Microflow != "" {
        lines = append(lines, fmt.Sprintf("%s  TARGETING GROUPS MICROFLOW %s", indent, us.Microflow))
    }
case *workflows.XPathGroupSource:
    if us.XPath != "" {
        lines = append(lines, fmt.Sprintf("%s  TARGETING GROUPS XPATH '%s'", indent, us.XPath))
    }
}

This shows that when reading from the model:

  • MicroflowBasedUserSource gets formatted as TARGETING USERS MICROFLOW
  • MicroflowGroupSource gets formatted as TARGETING GROUPS MICROFLOW

But in the AST, we only have one Kind="microflow" for both user and group microflow targeting? That doesn't seem right.

Let me re-examine the AST comment:

// Kind: "microflow", "xpath", "group_microflow", "group_xpath", or ""

And the executor buildUserTask:

switch n.Targeting.Kind {
case "microflow":
    task.UserSource = &workflows.MicroflowBasedUserSource{
        Microflow: n.Targeting.Microflow.Module + "." + n.Targeting.Microflow.Name,
    }
case "xpath":
    task.UserSource = &workflows.XPathBasedUserSource{
        XPath: n.Targeting.XPath,
    }
case "group_microflow":
    task.UserSource = &workflows.MicroflowGroupSource{
        Microflow: n.Targeting.Microflow.Module + "." + n.Targeting.Microflow.Name,
    }
case "group_xpath":
    task.UserSource = &workflows.XPathGroupSource{
        XPath: n.Targeting.XPath,
    }
}

This suggests:

  • Kind="microflow" -> MicroflowBasedUserSource (user targeting via microflow)
  • Kind="xpath" -> XPathBasedUserSource (user targeting via xpath)
  • Kind="group_microflow" -> MicroflowGroupSource (group targeting via microflow)
  • Kind="group_xpath" -> XPathGroupSource (group targeting via xpath)

But how do we represent the legacy syntax TARGETING MICROFLOW (without USERS)? According to the PR description, this should still be valid and treated as user targeting.

Looking at the test file:

-- TARGETING MICROFLOW (legacy short form)
USER TASK LegacyMF 'Legacy microflow targeting'
  PAGE WFTarget.TaskPage
  TARGETING MICROFLOW WFTarget.ACT_GetUsers
  OUTCOMES 'Done' { };

And in the executor formatUserTask, MicroflowBasedUserSource is formatted as TARGETING USERS MICROFLOW.

This creates a problem: when we read a legacy TARGETING MICROFLOW statement, we would store it as MicroflowBasedUserSource, but when we DESCRIBE it back out, we would get TARGETING USERS MICROFLOW, which is not the same as the original.

However, the PR description says: "TARGETING MICROFLOW (legacy short form, still valid)" and the test includes it, so it must be handled correctly.

Let me check how the visitor would distinguish these cases. The grammar is:

(TARGETING (USERS | GROUPS)? MICROFLOW qualifiedName)?

So for:

  • TARGETING MICROFLOW x.y: USERS|GROUPS is absent
  • TARGETING USERS MICROFLOW x.y: USERS|GROUPS = USERS
  • TARGETING GROUPS MICROFLOW x.y: USERS|GROUPS = GROUPS

The visitor would need to check if USERS|GROUPS was present and what it was to set the Kind correctly.

Given the Kind values in the AST comment, it seems:

  • If USERS|GROUPS is absent or USERS: Kind = "microflow" or "xpath" (user targeting)
  • If USERS|GROUPS is GROUPS: Kind = "group_microflow" or "group_xpath" (group targeting)

But then how does the executor know when to output USERS vs no USERS for the legacy case?

Looking at formatUserTask again:

case *workflows.MicroflowBasedUserSource:
    if us.Microflow != "" {
        lines = append(lines, fmt.Sprintf("%s  TARGETING USERS MICROFLOW %s", indent, us.Microflow))
    }

It always outputs USERS for MicroflowBasedUserSource, even if the original was legacy TARGETING MICROFLOW without USERS.

This suggests that the legacy form is being normalized to the explicit USERS form when read from the model, which is acceptable if the legacy form is treated as equivalent to TARGETING USERS MICROFLOW.

The PR description says: "Parser now reads both legacy UserSource and current UserTargeting BSON


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support TARGET USERS clause on workflow USER TASK definitions

2 participants